home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cocktail / reuse.lha / reuse / src / IO.mi < prev    next >
Text File  |  1992-08-18  |  17KB  |  697 lines

  1. (* $Id: IO.mi,v 1.9 1992/01/30 13:23:29 grosch rel $ *)
  2.  
  3. (* $Log: IO.mi,v $
  4.  * Revision 1.9  1992/01/30  13:23:29  grosch
  5.  * redesign of interface to operating system
  6.  *
  7.  * Revision 1.8  1991/11/21  14:33:17  grosch
  8.  * new version of RCS on SPARC
  9.  *
  10.  * Revision 1.7  91/06/07  12:19:51  grosch
  11.  * decreased bounds of flexible arrays
  12.  * 
  13.  * Revision 1.6  91/06/07  11:37:42  grosch
  14.  * increased bounds of flexible arrays
  15.  * 
  16.  * Revision 1.5  91/01/16  17:11:13  grosch
  17.  * fixed range check problem with BytesRead
  18.  * 
  19.  * Revision 1.4  89/08/18  11:11:48  grosch
  20.  * make Write work for Size = 0
  21.  * 
  22.  * Revision 1.3  89/07/14  16:27:15  grosch
  23.  * made WriteN work for numbers with MSBit set
  24.  * 
  25.  * Revision 1.2  89/01/25  19:37:28  grosch
  26.  * tuning: ReadC inline in Read and ReadS, WriteC inline in Write and WriteS
  27.  * 
  28.  * Revision 1.1  89/01/24  19:04:35  grosch
  29.  * added procedure UnRead
  30.  * 
  31.  * Revision 1.0  88/10/04  11:46:58  grosch
  32.  * Initial revision
  33.  * 
  34.  *)
  35.  
  36. (* Ich, Doktor Josef Grosch, Informatiker, Sept. 1987 *)
  37.  
  38. IMPLEMENTATION MODULE IO;            (* buffered IO        *)
  39.  
  40. FROM    SYSTEM    IMPORT ADDRESS    , ADR    ;
  41. FROM    General    IMPORT Exp2    , Exp10    ;
  42. FROM    Memory    IMPORT Alloc    , Free    ;
  43.  
  44. IMPORT    System;
  45.  
  46. CONST
  47.    EolCh        = 12C;
  48.    TabCh        = 11C;
  49.    BufferSize        = 1024;
  50.    MaxInt        = 2147483647;    (* 2 ** 31 - 1 *)
  51.    MaxPow10        = 1000000000;
  52.    MaxIntDiv10        = MaxInt DIV 10;
  53.  
  54. TYPE
  55.    BufferDescriptor    = RECORD
  56.      Buffer        : POINTER TO ARRAY [0 .. BufferSize] OF CHAR;
  57.      BufferIndex    : SHORTINT;
  58.      BytesRead    : SHORTINT;
  59.      OpenForOutput    : BOOLEAN;
  60.      EndOfFile    : BOOLEAN;
  61.      FlushLine    : BOOLEAN;
  62.       END;
  63.  
  64.    (* INV BufferIndex points before the character to be read next *)
  65.  
  66. VAR
  67.    BufferPool    : ARRAY tFile OF BufferDescriptor;
  68.    i        : tFile;
  69.    MyCHR    : ARRAY [0 .. 15] OF CHAR;
  70.  
  71. PROCEDURE FillBuffer    (f: tFile);
  72.    BEGIN
  73.       WITH BufferPool [f] DO
  74.      IF FlushLine THEN
  75.         WriteFlush (StdOutput);
  76.         WriteFlush (StdError );
  77.      END;
  78.      BufferIndex := 0;
  79.      BytesRead := System.Read (f, ADR (Buffer^ [1]), BufferSize);
  80.      IF BytesRead <= 0 THEN
  81.         BytesRead := 0;
  82.         EndOfFile := TRUE;
  83.      END;
  84.       END;
  85.    END FillBuffer;
  86.  
  87. PROCEDURE ReadOpen    (VAR FileName: ARRAY OF CHAR): tFile;
  88.    VAR                        (* open  input file    *)
  89.       f        : tFile;
  90.    BEGIN
  91.       f := System.OpenInput (FileName);
  92.       WITH BufferPool [f] DO
  93.      Buffer        := Alloc (BufferSize + 1);
  94.      BufferIndex    := 0;
  95.      BytesRead    := 0;
  96.      OpenForOutput    := FALSE;
  97.      EndOfFile    := FALSE;
  98.       END;
  99.       CheckFlushLine (f);
  100.       RETURN f;
  101.    END ReadOpen;
  102.  
  103. PROCEDURE ReadClose    (f: tFile);        (* close input file    *)
  104.    BEGIN
  105.       System.Close (f);
  106.       WITH BufferPool [f] DO
  107.      Free (BufferSize + 1, Buffer);
  108.      Buffer := NIL;
  109.       END;
  110.    END ReadClose;
  111.  
  112. PROCEDURE Read        (f: tFile; Buffer: ADDRESS; Size: CARDINAL): INTEGER;
  113.    VAR                        (* binary        *)
  114.       BufferPtr : POINTER TO ARRAY [0 .. 100000000] OF CHAR;
  115.       i        : CARDINAL;
  116.    BEGIN
  117.       BufferPtr := Buffer;
  118.       WITH BufferPool [f] DO
  119.      i := 0;
  120.      LOOP
  121.         IF i = Size THEN RETURN i; END;
  122.         IF BufferIndex = BytesRead THEN    (* ReadC inline        *)
  123.            FillBuffer (f);
  124.            IF EndOfFile THEN Buffer^ [1] := 0C; END;
  125.         END;
  126.         INC (BufferIndex);
  127.         BufferPtr^ [i] := Buffer^ [BufferIndex];
  128.         IF EndOfFile THEN RETURN i; END;
  129.         INC (i);
  130.      END;
  131.       END;
  132.    END Read;
  133.  
  134. PROCEDURE ReadC        (f: tFile): CHAR;    (* character        *)
  135.    BEGIN
  136.       WITH BufferPool [f] DO
  137.      IF BufferIndex = BytesRead THEN
  138.         FillBuffer (f);
  139.         IF EndOfFile THEN Buffer^ [1] := 0C; END;
  140.      END;
  141.      INC (BufferIndex);
  142.      RETURN Buffer^ [BufferIndex];
  143.       END;
  144.    END ReadC;
  145.  
  146. PROCEDURE ReadI        (f: tFile): INTEGER;    (* integer  number    *)
  147.    VAR
  148.       n        : INTEGER;
  149.       ch    : CHAR;
  150.       negative    : BOOLEAN;
  151.    BEGIN
  152.       REPEAT
  153.          ch := ReadC (f);
  154.       UNTIL (ch # ' ') AND (ch # TabCh) AND (ch # EolCh);
  155.       CASE ch OF
  156.       |  '+' : negative := FALSE; ch := ReadC (f);
  157.       |  '-' : negative := TRUE ; ch := ReadC (f);
  158.       ELSE     negative := FALSE;
  159.       END;
  160.       n := 0;
  161.       WHILE ('0' <= ch) AND (ch <= '9') DO
  162.      n := 10 * n + INTEGER (ORD (ch) - ORD ('0'));
  163.      ch := ReadC (f);
  164.       END;
  165.       DEC (BufferPool [f].BufferIndex);
  166.       IF negative
  167.       THEN RETURN - n;
  168.       ELSE RETURN   n;
  169.       END;
  170.    END ReadI;
  171.  
  172. PROCEDURE ReadR        (f: tFile): REAL;    (* real     number    *)
  173.    VAR
  174.       n            : REAL;
  175.       Mantissa        : LONGCARD;
  176.       Exponent        : INTEGER;
  177.       MantissaNeg    : BOOLEAN;
  178.       ExponentNeg    : BOOLEAN;
  179.       FractionDigits    : CARDINAL;
  180.       TruncatedDigits    : CARDINAL;
  181.       ch        : CHAR;
  182.    BEGIN
  183.       MantissaNeg    := FALSE;
  184.       Mantissa        := 0;
  185.       Exponent        := 0;
  186.       FractionDigits    := 0;
  187.       TruncatedDigits    := 0;
  188.  
  189.       REPEAT                    (* skip white space    *)
  190.      ch := ReadC (f);
  191.       UNTIL (ch # ' ') AND (ch # TabCh) AND (ch # EolCh);
  192.  
  193.       CASE ch OF                (* handle sign        *)
  194.       | '+' : ch := ReadC (f);
  195.       | '-' : ch := ReadC (f); MantissaNeg := TRUE;
  196.       | 'E' : Mantissa := 1;
  197.       ELSE
  198.       END;
  199.  
  200.       WHILE ('0' <= ch) AND (ch <= '9') DO    (* integer part        *)
  201.      IF Mantissa <= MaxIntDiv10 THEN
  202.         Mantissa := 10 * Mantissa;
  203.         IF Mantissa <= MaxInt - (ORD (ch) - ORD ('0')) THEN
  204.            INC (Mantissa, ORD (ch) - ORD ('0'));
  205.         ELSE
  206.            INC (TruncatedDigits);
  207.         END;
  208.      ELSE
  209.         INC (TruncatedDigits);
  210.      END;
  211.      ch := ReadC (f);
  212.       END;
  213.  
  214.       IF ch = '.' THEN ch := ReadC (f); END;    (* decimal point    *)
  215.  
  216.       WHILE ('0' <= ch) AND (ch <= '9') DO    (* fractional part    *)
  217.      IF Mantissa <= MaxIntDiv10 THEN
  218.         Mantissa := 10 * Mantissa;
  219.         IF Mantissa <= MaxInt - (ORD (ch) - ORD ('0')) THEN
  220.            INC (Mantissa, ORD (ch) - ORD ('0'));
  221.         ELSE
  222.            INC (TruncatedDigits);
  223.         END;
  224.      ELSE
  225.         INC (TruncatedDigits);
  226.      END;
  227.      INC (FractionDigits);
  228.      ch := ReadC (f);
  229.       END;
  230.  
  231.       IF ch = 'E' THEN                (* exponent        *)
  232.      ch := ReadC (f);
  233.  
  234.      CASE ch OF
  235.      |  '+' : ExponentNeg := FALSE; ch := ReadC (f);
  236.      |  '-' : ExponentNeg := TRUE ; ch := ReadC (f);
  237.      ELSE     ExponentNeg := FALSE;
  238.      END;
  239.  
  240.      WHILE ('0' <= ch) AND (ch <= '9') DO
  241.         Exponent := 10 * Exponent + INTEGER (ORD (ch) - ORD ('0'));
  242.         ch := ReadC (f);
  243.      END;
  244.  
  245.      IF ExponentNeg THEN
  246.         Exponent := - Exponent;
  247.      END;
  248.       END;
  249.  
  250.       DEC (BufferPool [f].BufferIndex);
  251.       DEC (Exponent, FractionDigits - TruncatedDigits);
  252.       n := FLOAT (Mantissa) * Exp10 (Exponent);
  253.       IF MantissaNeg
  254.       THEN RETURN - n;
  255.       ELSE RETURN   n;
  256.       END;
  257.    END ReadR;
  258.  
  259. PROCEDURE ReadB        (f: tFile): BOOLEAN;    (* boolean        *)
  260.    BEGIN
  261.       RETURN ReadC (f) = 'T';
  262.    END ReadB;
  263.  
  264. PROCEDURE ReadN        (f: tFile; Base: INTEGER): INTEGER;
  265.    VAR                        (* number of base 'Base'*)
  266.       n        : INTEGER;
  267.       ch    : CHAR;
  268.       digit    : INTEGER;
  269.    BEGIN
  270.       REPEAT
  271.      ch := ReadC (f);
  272.       UNTIL (ch # ' ') AND (ch # TabCh) AND (ch # EolCh);
  273.       n := 0;
  274.       LOOP
  275.      IF ('0' <= ch) AND (ch <= '9') THEN
  276.         digit := ORD (ch) - ORD ('0');
  277.      ELSIF ('A' <= ch) AND (ch <= 'F') THEN
  278.         digit := ORD (ch) - ORD ('A') + 10;
  279.      ELSE
  280.         digit := 99;
  281.      END;
  282.      IF digit >= Base THEN EXIT; END;
  283.      n := Base * n + digit;
  284.      ch := ReadC (f);
  285.       END;
  286.       DEC (BufferPool [f].BufferIndex);
  287.       RETURN n;
  288.    END ReadN;
  289.  
  290. PROCEDURE ReadS        (f: tFile; VAR s: ARRAY OF CHAR);
  291.    VAR i    : CARDINAL;            (* string        *)
  292.    BEGIN
  293.       WITH BufferPool [f] DO
  294.      FOR i := 0 TO HIGH (s) DO
  295.         IF BufferIndex = BytesRead THEN    (* ReadC inline        *)
  296.            FillBuffer (f);
  297.            IF EndOfFile THEN Buffer^ [1] := 0C; END;
  298.         END;
  299.         INC (BufferIndex);
  300.         s [i] := Buffer^ [BufferIndex];
  301.      END;
  302.       END;
  303.    END ReadS;
  304.  
  305. PROCEDURE ReadShort    (f: tFile): SHORTINT;    (* shortint number    *)
  306.    BEGIN
  307.       RETURN ReadI (f);
  308.    END ReadShort;
  309.  
  310. PROCEDURE ReadLong    (f: tFile): LONGINT;    (* longint  number    *)
  311.    BEGIN
  312.       RETURN ReadI (f);
  313.    END ReadLong;
  314.  
  315. PROCEDURE ReadCard    (f: tFile): CARDINAL;    (* cardinal number    *)
  316.    BEGIN
  317.       RETURN ReadI (f);
  318.    END ReadCard;
  319.  
  320. PROCEDURE ReadNl    (f: tFile);        (* new line        *)
  321.    BEGIN
  322.       REPEAT
  323.       UNTIL ReadC (f) = EolCh;
  324.    END ReadNl;
  325.  
  326. PROCEDURE UnRead    (f: tFile);        (* backspace 1 char.    *)
  327.    BEGIN
  328.       DEC (BufferPool [f].BufferIndex);
  329.    END UnRead;
  330.  
  331.  
  332. PROCEDURE EndOfLine    (f: tFile): BOOLEAN;    (* end of line ?    *)
  333.    VAR ch : CHAR;
  334.    BEGIN
  335.       WITH BufferPool [f] DO
  336.      IF BufferIndex = BytesRead THEN
  337.         FillBuffer (f);
  338.         IF EndOfFile THEN Buffer^ [1] := 0C; END;
  339.      END;
  340.      RETURN Buffer^ [BufferIndex + 1] = EolCh;
  341.       END;
  342.    END EndOfLine;
  343.  
  344. PROCEDURE EndOfFile    (f: tFile): BOOLEAN;    (* end of file ?    *)
  345.    VAR ch : CHAR;
  346.    BEGIN
  347.       ch := ReadC (f);
  348.       DEC (BufferPool [f].BufferIndex);
  349.       RETURN BufferPool [f].EndOfFile;
  350.    END EndOfFile;
  351.  
  352.  
  353. PROCEDURE CheckFlushLine (f: tFile);
  354.    BEGIN
  355.       BufferPool [f].FlushLine := System.IsCharacterSpecial (f);
  356.    END CheckFlushLine;
  357.  
  358. PROCEDURE WriteOpen    (VAR FileName: ARRAY OF CHAR): tFile;
  359.    VAR                        (* open  output file    *)
  360.       f        : tFile;
  361.    BEGIN
  362.       f := System.OpenOutput (FileName);
  363.       WITH BufferPool [f] DO
  364.      Buffer        := Alloc (BufferSize + 1);
  365.      BufferIndex    := 0;
  366.      OpenForOutput    := TRUE;
  367.       END;
  368.       CheckFlushLine (f);
  369.       RETURN f;
  370.    END WriteOpen;
  371.  
  372. PROCEDURE WriteClose    (f: tFile);        (* close output file    *)
  373.    BEGIN
  374.       WriteFlush (f);
  375.       System.Close (f);
  376.       WITH BufferPool [f] DO
  377.      Free (BufferSize + 1, Buffer);
  378.      Buffer := NIL;
  379.       END;
  380.    END WriteClose;
  381.  
  382. PROCEDURE WriteFlush    (f: tFile);        (* flush output buffer    *)
  383.    BEGIN
  384.       WITH BufferPool [f] DO
  385.      BytesRead := System.Write (f, ADR (Buffer^ [1]), BufferIndex);
  386.      BufferIndex := 0;
  387.       END;
  388.    END WriteFlush;
  389.  
  390. PROCEDURE Write        (f: tFile; Buffer: ADDRESS; Size: INTEGER): INTEGER;
  391.    VAR                        (* binary        *)
  392.       BufferPtr : POINTER TO ARRAY [0 .. 100000000] OF CHAR;
  393.       i        : INTEGER;
  394.    BEGIN
  395.       BufferPtr := Buffer;
  396.       WITH BufferPool [f] DO
  397.      FOR i := 0 TO Size - 1 DO
  398.         INC (BufferIndex);            (* WriteC inline    *)
  399.         Buffer^ [BufferIndex] := BufferPtr^ [i];
  400.         IF (BufferIndex = BufferSize) THEN WriteFlush (f); END;
  401.      END;
  402.       END;
  403.       RETURN Size;
  404.    END Write;
  405.  
  406. PROCEDURE WriteC    (f: tFile; c: CHAR);    (* character        *)
  407.    BEGIN
  408.       WITH BufferPool [f] DO
  409.      INC (BufferIndex);
  410.      Buffer^ [BufferIndex] := c;
  411.      IF (BufferIndex = BufferSize) OR FlushLine AND (c = EolCh) THEN
  412.         WriteFlush (f);
  413.      END;
  414.       END;
  415.    END WriteC;
  416.  
  417. PROCEDURE WriteI    (f: tFile; n: INTEGER ; FieldWidth: CARDINAL);
  418.    VAR                        (* integer  number    *)
  419.       i        : INTEGER;
  420.       length    : CARDINAL;
  421.       negative    : CARDINAL;
  422.       digits    : ARRAY [0 .. 10] OF CHAR;
  423.    BEGIN
  424.       IF n < 0 THEN
  425.      negative := 1;
  426.      n := - n;
  427.       ELSE
  428.      negative := 0;
  429.       END;
  430.       length := 0;
  431.       REPEAT
  432.      INC (length);
  433.      digits [length] := MyCHR [n MOD 10];
  434.      n := n DIV 10;
  435.       UNTIL n = 0;
  436.       FOR i := 1 TO INTEGER (FieldWidth - length - negative) DO
  437.      WriteC (f, ' ');
  438.       END;
  439.       IF negative = 1 THEN WriteC (f, '-'); END;
  440.       FOR i := INTEGER (length) TO 1 BY -1 DO
  441.      WriteC (f, digits [i]);
  442.       END;
  443.    END WriteI;
  444.  
  445. PROCEDURE WriteR    (f: tFile; n: REAL; Before, After, Exp: CARDINAL);
  446.    CONST                    (* real   number    *)
  447.       StartIndex    = 100;
  448.    VAR
  449.       i            : CARDINAL;
  450.       j            : INTEGER;
  451.       FirstDigit    : CARDINAL;
  452.       IntegerDigits    : CARDINAL;
  453.       TotalDigits    : CARDINAL;
  454.       IsNegative    : CARDINAL;
  455.       Digits        : ARRAY [0 .. 200] OF CARDINAL;
  456.       MaxCard        : REAL;
  457.       MaxCardDiv10    : REAL;
  458.       Mantissa        : LONGCARD;
  459.       Exponent        : INTEGER;
  460.    BEGIN
  461.       MaxCard        := FLOAT (MaxInt);
  462.       MaxCardDiv10    := FLOAT (MaxIntDiv10);
  463.  
  464.       IF n < 0.0 THEN                (* determine sign    *)
  465.      IsNegative := 1;
  466.      n := - n;
  467.       ELSE
  468.      IsNegative := 0;
  469.       END;
  470.  
  471.       IF n = 0.0 THEN        (* determine mantissa and exponent    *)
  472.      Mantissa := 0;
  473.      Exponent := 1;
  474.       ELSE
  475.      Exponent := 10;            (* normalize mantissa    *)
  476.      WHILE n > MaxCard DO
  477.         n := n / 10.0;
  478.         INC (Exponent);
  479.      END;
  480.      WHILE n <= MaxCardDiv10 DO
  481.         n := n * 10.0;
  482.         DEC (Exponent);
  483.      END;
  484.      Mantissa := TRUNC (n);
  485.      IF Mantissa < MaxPow10 THEN
  486.         DEC (Exponent);
  487.      END;
  488.       END;
  489.                               (* determine size of:    *)
  490.       IF (Exp > 0) OR (Exponent <= 0) THEN    (* integer part        *)
  491.      IntegerDigits := 1;
  492.       ELSE
  493.      IntegerDigits := Exponent;
  494.       END;
  495.       IF After = 0 THEN After := 1; END;    (* fractional part    *)
  496.       TotalDigits := IntegerDigits + After;    (* total # of digits    *)
  497.  
  498.       FirstDigit := StartIndex;            (* convert mantissa    *)
  499.       REPEAT
  500.      DEC (FirstDigit);
  501.      Digits [FirstDigit] := Mantissa MOD 10;
  502.      Mantissa := Mantissa DIV 10;
  503.       UNTIL Mantissa = 0;
  504.       IF Exp = 0 THEN                (* add leading zeroes    *)
  505.      FOR j := 1 TO 1 - Exponent DO
  506.         DEC (FirstDigit);
  507.         Digits [FirstDigit] := 0;
  508.      END;
  509.       END;
  510.       FOR i := StartIndex TO FirstDigit + TotalDigits DO
  511.      Digits [i] := 0;            (* add trailing zeroes    *)
  512.       END;
  513.  
  514.       Digits [FirstDigit - 1] := 0;        (* round mantissa    *)
  515.       IF Digits [FirstDigit + TotalDigits] >= 5 THEN
  516.      i := FirstDigit + TotalDigits - 1;
  517.      WHILE Digits [i] = 9 DO        (* carry        *)
  518.         Digits [i] := 0;
  519.         DEC (i);
  520.      END;
  521.      INC (Digits [i]);
  522.      IF i = FirstDigit - 1 THEN (* carry at most significant pos.    *)
  523.         FirstDigit := i;
  524.         IF Exp > 0 THEN
  525.            INC (Exponent);
  526.         ELSIF Exponent > 0 THEN
  527.            INC (IntegerDigits);
  528.         END;
  529.      END;
  530.       END;
  531.                         (* print mantissa    *)
  532.       FOR j := 1 TO INTEGER (Before - IsNegative - IntegerDigits) DO
  533.      WriteC (f, ' ');            (* leading spaces    *)
  534.       END;
  535.       IF IsNegative = 1 THEN WriteC (f, '-'); END;    (* sign        *)
  536.       FOR i :=  1 TO IntegerDigits DO        (* integer part        *)
  537.      WriteC (f, MyCHR [Digits [FirstDigit]]);
  538.      INC (FirstDigit);
  539.       END;
  540.       WriteC (f, '.');                (* decimal point    *)
  541.       FOR i :=  1 TO After DO            (* fractional part    *)
  542.      WriteC (f, MyCHR [Digits [FirstDigit]]);
  543.      INC (FirstDigit);
  544.       END;
  545.  
  546.       IF Exp > 0 THEN                (* print exponent    *)
  547.      DEC (Exponent);
  548.      WriteC (f, 'E');
  549.      IF Exponent < 0 THEN
  550.         WriteC (f, '-');
  551.         Exponent := - Exponent;
  552.      ELSE
  553.         WriteC (f, '+');
  554.      END;
  555.      WriteN (f, Exponent, Exp - 1, 10);
  556.       END;
  557.    END WriteR;
  558.  
  559. PROCEDURE WriteB    (f: tFile; b: BOOLEAN);    (* boolean        *)
  560.    BEGIN
  561.       IF b
  562.       THEN WriteC (f, 'T');
  563.       ELSE WriteC (f, 'F');
  564.       END;
  565.    END WriteB;
  566.  
  567. PROCEDURE WriteN    (f: tFile; n: LONGCARD; FieldWidth, Base: CARDINAL);
  568.    VAR                        (* number of base 'Base'*)
  569.       i        : INTEGER;
  570.       length    : CARDINAL;
  571.       digits    : ARRAY [0 .. 32] OF CHAR;
  572.    BEGIN
  573.       length := 0;
  574.       REPEAT
  575.      INC (length);
  576.      digits [length] := MyCHR [n MOD Base];
  577.      n := n DIV Base;
  578.       UNTIL n = 0;
  579.       FOR i := 1 TO INTEGER (FieldWidth - length) DO
  580.      WriteC (f, '0');
  581.       END;
  582.       FOR i := INTEGER (length) TO 1 BY -1 DO
  583.      WriteC (f, digits [i]);
  584.       END;
  585.    END WriteN;
  586.  
  587. PROCEDURE WriteS    (f: tFile; VAR s: ARRAY OF CHAR); 
  588.    VAR i    : CARDINAL;            (* string        *)
  589.    VAR c    : CHAR;
  590.    BEGIN
  591.       WITH BufferPool [f] DO
  592.      FOR i := 0 TO HIGH (s) DO
  593.         c := s [i];
  594.         IF c = 0C THEN RETURN; END;
  595.         INC (BufferIndex);            (* WriteC inline    *)
  596.         Buffer^ [BufferIndex] := c;
  597.         IF (BufferIndex = BufferSize) OR FlushLine AND (c = EolCh) THEN
  598.            WriteFlush (f);
  599.         END;
  600.      END;
  601.       END;
  602.    END WriteS;
  603.  
  604. PROCEDURE WriteShort    (f: tFile; n: SHORTINT; FieldWidth: CARDINAL);
  605.    BEGIN                    (* shortint number    *)
  606.       WriteI (f, n, FieldWidth);
  607.    END WriteShort;
  608.  
  609. PROCEDURE WriteLong    (f: tFile; n: LONGINT ; FieldWidth: CARDINAL);
  610.    BEGIN                    (* longint  number    *)
  611.       WriteI (f, n, FieldWidth);
  612.    END WriteLong;
  613.  
  614. PROCEDURE WriteCard    (f: tFile; n: CARDINAL; FieldWidth: CARDINAL);
  615.    VAR                        (* cardinal number    *)
  616.       i        : INTEGER;
  617.       length    : CARDINAL;
  618.       digits    : ARRAY [0 .. 10] OF CHAR;
  619.    BEGIN
  620.       length := 0;
  621.       REPEAT
  622.      INC (length);
  623.      digits [length] := MyCHR [n MOD 10];
  624.      n := n DIV 10;
  625.       UNTIL n = 0;
  626.       FOR i := 1 TO INTEGER (FieldWidth - length) DO
  627.      WriteC (f, ' ');
  628.       END;
  629.       FOR i := INTEGER (length) TO 1 BY -1 DO
  630.      WriteC (f, digits [i]);
  631.       END;
  632.    END WriteCard;
  633.  
  634. PROCEDURE WriteNl    (f: tFile);        (* new line        *)
  635.    BEGIN
  636.       WriteC (f, EolCh);
  637.    END WriteNl;
  638.  
  639.  
  640. PROCEDURE CloseIO;                (* close all files    *)
  641.    VAR i    : tFile;
  642.    BEGIN
  643.       FOR i := 0 TO System.cMaxFile DO
  644.      WITH BufferPool [i] DO
  645.         IF Buffer # NIL THEN
  646.            IF OpenForOutput THEN
  647.           WriteClose (i);
  648.            ELSE
  649.           ReadClose (i);
  650.            END;
  651.         END;
  652.      END;
  653.       END;
  654.    END CloseIO;
  655.  
  656. BEGIN
  657.    MyCHR [ 0] := '0';
  658.    MyCHR [ 1] := '1';
  659.    MyCHR [ 2] := '2';
  660.    MyCHR [ 3] := '3';
  661.    MyCHR [ 4] := '4';
  662.    MyCHR [ 5] := '5';
  663.    MyCHR [ 6] := '6';
  664.    MyCHR [ 7] := '7';
  665.    MyCHR [ 8] := '8';
  666.    MyCHR [ 9] := '9';
  667.    MyCHR [10] := 'A';
  668.    MyCHR [11] := 'B';
  669.    MyCHR [12] := 'C';
  670.    MyCHR [13] := 'D';
  671.    MyCHR [14] := 'E';
  672.    MyCHR [15] := 'F';
  673.  
  674.    FOR i := 0 TO System.cMaxFile DO
  675.       WITH BufferPool [i] DO
  676.      Buffer        := NIL;
  677.      BufferIndex    := 0;
  678.      BytesRead    := 0;
  679.      OpenForOutput    := FALSE;
  680.      EndOfFile    := FALSE;
  681.      FlushLine    := FALSE;
  682.       END;
  683.    END;
  684.  
  685.    BufferPool [StdInput ].Buffer := Alloc (BufferSize + 1);
  686.    BufferPool [StdOutput].Buffer := Alloc (BufferSize + 1);
  687.    BufferPool [StdError ].Buffer := Alloc (BufferSize + 1);
  688.  
  689.    BufferPool [StdInput ].OpenForOutput := FALSE;
  690.    BufferPool [StdOutput].OpenForOutput := TRUE;
  691.    BufferPool [StdError ].OpenForOutput := TRUE;
  692.  
  693.    CheckFlushLine (StdInput );
  694.    CheckFlushLine (StdOutput);
  695.    CheckFlushLine (StdError );
  696. END IO.
  697.